package twoD.Csg;

import oneD.fem.algorithm.MyLinalg;
import inf.jlinalg.Array2DMatrix;
import inf.jlinalg.ArrayVector;
import inf.jlinalg.BLAM;
import inf.jlinalg.IMatrix;
import inf.jlinalg.IVector;

public class Transformation {
	private IMatrix H;
	private int d;

	public Transformation() {

	}

	protected void setD(int d) {
		this.d = d;
		H = new Array2DMatrix(d + 1, d + 1);
		for (int i = 0; i < d + 1; i++)
			H.set(i, i, 1);
	}

	protected int getD() {
		return d;
	}

	public IMatrix getH() {
		return H;
	}

	/**
	 * 
	 * @return the inverse of transformation matrix H
	 */
	public IMatrix getH1() {
		IMatrix H1 = (IMatrix) H.clone();
		if (d == 2) {
			double a1 = H.get(0, 0);
			double b1 = H.get(0, 1);
			double c1 = H.get(0, 2);
			double a2 = H.get(1, 0);
			double b2 = H.get(1, 1);
			double c2 = H.get(1, 2);
			double det = a1 * b2 - a2 * b1;
			H1.set(0, 0, b2 / det);
			H1.set(0, 1, -b1 / det);
			H1.set(0, 2, (b1 * c2 - b2 * c1) / det);
			H1.set(1, 0, -a2 / det);
			H1.set(1, 1, a1 / det);
			H1.set(1, 2, (a2 * c1 - a1 * c2) / det);
		} else if (d == 3) {
			double a1 = H.get(0, 0);
			double b1 = H.get(0, 1);
			double c1 = H.get(0, 2);
			double d1 = H.get(0, 3);
			double a2 = H.get(1, 0);
			double b2 = H.get(1, 1);
			double c2 = H.get(1, 2);
			double d2 = H.get(1, 3);
			double a3 = H.get(2, 0);
			double b3 = H.get(2, 1);
			double c3 = H.get(2, 2);
			double d3 = H.get(2, 3);
			double det = MyLinalg.det3x3(a1, b1, c1, a2, b2, c2, a3, b3, c3);
			H1.set(0, 0, MyLinalg.det2x2(b2, c2, b3, c3) / det);
			H1.set(0, 1, -MyLinalg.det2x2(b1, c1, b3, c3) / det);
			H1.set(0, 2, MyLinalg.det2x2(b1, c1, b2, c2) / det);
			H1.set(0, 3, -MyLinalg.det3x3(b1, c1, d1, b2, c2, d2, b3, c3, d3)
					/ det);
			H1.set(1, 0, -MyLinalg.det2x2(a2, c2, a3, c3) / det);
			H1.set(1, 1, MyLinalg.det2x2(a1, c1, a3, c3) / det);
			H1.set(1, 2, -MyLinalg.det2x2(a1, c1, a2, c2) / det);
			H1.set(1, 3, MyLinalg.det3x3(a1, c1, d1, a2, c2, d2, a3, c3, d3)
					/ det);
			H1.set(2, 0, MyLinalg.det2x2(a2, b2, a3, b3) / det);
			H1.set(2, 1, -MyLinalg.det2x2(a1, b1, a3, b3) / det);
			H1.set(2, 2, MyLinalg.det2x2(a1, b1, a2, b2) / det);
			H1.set(2, 3, -MyLinalg.det3x3(a1, b1, d1, a2, b2, d2, a3, b3, d3)
					/ det);
		}
		return H1;
	}

	public double[] multiply(double... p) {
		int n = p.length;
		IVector ptilde = new ArrayVector(n + 1);
		for (int i = 0; i < n; i++)
			ptilde.set(i, p[i]);
		ptilde.set(n, 1);
		IVector phat = (IVector) ptilde.clone();
		BLAM.multiply(1, BLAM.NO_TRANSPOSE, H, ptilde, 0, phat);
		double[] res = new double[n];
		for (int i = 0; i < n; i++)
			res[i] = phat.get(i);
		return res;
	}

	public Transformation multiply(Transformation T) {
		Transformation newT = new Transformation();
		newT.setD(T.getD());
		IMatrix tmp = newT.getH();
		BLAM.multiply(1, BLAM.NO_TRANSPOSE, T.getH(), BLAM.NO_TRANSPOSE,
				getH(), 0.0, tmp);
		return newT;
	}
}
